package sq

import (
	"fmt"
	"strings"
)

// SQL 表达式
type expr struct {
	expr string
	args []interface{}
}

// Expr 生成原始SQL表达式，例如:
//  sq.Table("user").Update(map[string]interface{}{"price", sq.Expr("price * ? + ?", 2, 100)})
func Expr(expression string, args ...interface{}) *expr {
	return &expr{expr: expression, args: args}
}

// SQL语句构造器
type SqlBuilder struct {
	dialect    Dialect // SQL数据库方言(例如:mysql,mssql...)
	fields     string  // 数据库表中的字段
	table      string  // 数据库表名
	forceIndex string  // 强制使用索引
	where      string
	order      string
	limit      string
	offset     string
	hint       string  // 查询优化器提示
	args       []interface{} // where子句中要替换的额外args
}

func (s *SqlBuilder) limitFormat() string {
	if s.limit != "" {
		return fmt.Sprintf("LIMIT %s", s.limit)
	}
	return ""
}

func (s *SqlBuilder) offsetFormat() string {
	if s.offset != "" {
		return fmt.Sprintf("OFFSET %s", s.offset)
	}
	return ""
}

func (s *SqlBuilder) orderFormat() string {
	if s.order != "" {
		return fmt.Sprintf("ORDER BY %s", s.order)
	}
	return ""
}

//queryString 组装查询语句。
func (s *SqlBuilder) queryString() string {
	if s.fields == "" {
		s.fields = "*"
	}

	table := s.dialect.Quote(s.table) // 在表名上加上 ``，例如: `user`表
	if s.forceIndex != "" {
		table += fmt.Sprintf(" force index(%s)", s.forceIndex)
	}

	query := fmt.Sprintf("%sSELECT %s FROM %s %s %s %s %s", s.hint, s.fields, table, s.where, s.orderFormat(), s.limitFormat(), s.offsetFormat())
	query = strings.TrimRight(query, " ")
	query = query + ";"

	return query
}

//countString 组装count语句
func (s *SqlBuilder) countString() string {
	query := fmt.Sprintf("%sSELECT count(*) FROM %s %s", s.hint, s.dialect.Quote(s.table), s.where)
	query = strings.TrimRight(query, " ")
	query = query + ";"

	return query
}

//insertString 组装插入语句
func (s *SqlBuilder) insertString(params map[string]interface{}) string {
	var cols, values []string
	for _, k := range sortedParamKeys(params) { //该函数在2_util.go中
		cols = append(cols, s.dialect.Quote(k))
		values = append(values, "?")
		s.args = append(s.args, params[k])
	}

	return fmt.Sprintf("INSERT INTO %s (%s) VALUES(%s);", s.dialect.Quote(s.table), strings.Join(cols, ","), strings.Join(values, ","))
}

//updateString 组装更新语句
func (s *SqlBuilder) updateString(params map[string]interface{}) string {
	var updateFields []string
	args := make([]interface{}, 0)

	for _, k := range sortedParamKeys(params) {
		if e, ok := params[k].(*expr); ok {
			updateFields = append(updateFields, fmt.Sprintf("%s=%s", s.dialect.Quote(k), e.expr))
			args = append(args, e.args...)
		} else {
			updateFields = append(updateFields, fmt.Sprintf("%s=?", s.dialect.Quote(k)))
			args = append(args, params[k])
		}
	}
	args = append(args, s.args...)
	s.args = args

	query := fmt.Sprintf("UPDATE %s SET %s %s", s.dialect.Quote(s.table), strings.Join(updateFields, ","), s.where)
	query = strings.TrimRight(query, " ")
	query = query + ";"
	return query
}

//deleteString 组装删除语句
func (s *SqlBuilder) deleteString() string {
	query := fmt.Sprintf("DELETE FROM %s %s", s.dialect.Quote(s.table), s.where)
	query = strings.TrimRight(query, " ")
	query = query + ";"
	return query
}

func (s *SqlBuilder) Where(str string, args ...interface{}) {
	if s.where != "" {
		s.where = fmt.Sprintf("%s AND (%s)", s.where, str)
	} else {
		s.where = fmt.Sprintf("WHERE (%s)", str)
	}

	// 将 args存入 s.args中
	if args != nil {
		if s.args == nil {
			s.args = args
		} else {
			s.args = append(s.args, args...)
		}
	}
}
